﻿#ifndef __UTIL_M__
#define __UTIL_M__

#include <iostream>
#include <fstream>
#include <string>
#include <sys/stat.h>
#include <experimental/filesystem>

namespace Cloud
{
    namespace fs = std::experimental::filesystem;
    class FileUtil
    {
    public:
        FileUtil(const std::string &filename):_filename(filename)
        {}

        bool Remove()//删除文件
        {
            if(Exists() == false) return true;
            if(remove(_filename.c_str()) == 0) return true;
            return false;
        }
        int64_t FileSize()//获取文件大小
        {
            struct stat st;
            if(stat(_filename.c_str(), &st) < 0)
            {
                std::cout << "获取文件大小失败\n";
                return -1;
            }
            return st.st_size;
        }
        time_t LastModTime()//最新修改时间
        {
            struct stat st;
            if(stat(_filename.c_str(), &st) < 0)
            {
                std::cout << "获取文件最新修改时间失败\n";
                return -1;
            }
            return st.st_mtime;
        }
        time_t LastAccTime()//在实现热点重传的时候，要根据一个文件的最新访问时间，来判断该文件是否是热点文件
        {
            struct stat st;
            if(stat(_filename.c_str(), &st) < 0)
            {
                std::cout << "获取文件最新访问时间失败\n";
                return -1;
            }
            return st.st_atime;
        }
        std::string FileName()
        {
            //./a/b/c/file.txt
            size_t pos = _filename.find_last_of("\\");//找到最后一个/的位置
            if(pos == std::string::npos)
            {
                //说明该filename就是文件名
                return _filename;
            }
            return _filename.substr(pos+1);//仅返回文件名
        }
        bool GetPosLen(std::string *body, size_t pos, size_t len)//获取指定位置开始的指定长度的内容
        {
            //如果想要获取的内容长度大于文件的长度
            int64_t FSize = FileSize();
            if(pos + len > FSize)
            {
                std::cout << "获取长度错误\n";
                return false;
            }

            std::ifstream ifs;
            ifs.open(_filename, std::ios::binary);
            if(ifs.is_open() == false)
            {
                std::cout << "GetPosLen, 打开文件失败\n";
                return false;
            }
            ifs.seekg(pos, std::ios::beg);//从开始位置偏移pos
            body->resize(len);
            ifs.read(&(*body)[0], len);
            if(ifs.good() == false)
            {
                std::cout << "GetPosLen, 读取文件失败\n";
                ifs.close();
                return false;
            }
            ifs.close();
            return true; 
        }
        bool GetContent(std::string *body)//获取文件内容
        {
            int64_t FSize = FileSize();
            return GetPosLen(body, 0, FSize);
        }
        bool SetContent(const std::string &body)//向文件中写入内容
        {
            std::ofstream ofs;
            ofs.open(_filename, std::ios::binary);
            if(ofs.is_open() == false)
            {
                std::cout << "SetContent, 打开文件失败\n";
                return false;
            }
            ofs.write(&body[0], body.size());
            if(ofs.good() == false)
            {
                std::cout << "SetContent, 写入失败\n";
                ofs.close();
                return false;
            }
            ofs.close();
            return true;
        }
        bool Exists()
        {
            return fs::exists(_filename);
        }
        bool CreateDirectory()//创建目录
        {
            if(Exists()) return true;
            //创建目录
            return fs::create_directories(_filename);
        }
        bool ScanDirectory(std::vector<std::string> *array)//浏览目录，并将文件路径插入到array中
        {
            for(auto& p : fs::directory_iterator(_filename))//p并不是字符串
            {
                if(fs::is_directory(p)) continue;//如果是目录的话就直接跳过
                //relative_path()带有路径的文件名   .string()将其转化为字符串类型
                //先构建一个路径类，然后去获取相对路径，再将其转化为字符串类型
                array->push_back(fs::path(p).relative_path().string());
            }
            return true;
        }
    private:
        std::string _filename;
    };

    //class JsonUtil
    //{
    //public:
    //    static bool Serialize(const Json::Value &root, std::string *str)
    //    {
    //        //序列化
    //        Json::StreamWriterBuilder swb;
    //        std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
    //        std::stringstream ss;
    //        if(sw->write(root, &ss) != 0)
    //        {
    //            std::cout << "Serialize, 序列化失败,请检查字符流是否正确\n";
    //            return false;
    //        }
    //        *str = ss.str();
    //        return true;
    //    }
    //    static bool UnSerialize(const std::string &str, Json::Value *root)
    //    {
    //        //反序列化
    //        Json::CharReaderBuilder crb;
    //        std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
    //        std::string errs;
    //        bool ret = cr->parse(str.c_str(), str.c_str()+str.size(), root, &errs);
    //        if(ret == false)
    //        {
    //            std::cout << errs << "UnSerialize, 反序列化失败\n";
    //            return false;
    //        }
    //        return true;
    //    }
    //};
}
#endif